package com.ruoyi.wx.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.http.HttpServletRequestUtils;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.skm.domain.SkmOrderPayT;
import com.ruoyi.skm.service.ISkmOrderPayTService;
import com.ruoyi.utils.WxUrl;
import com.ruoyi.wx.service.SkmWxPayService;
import com.ruoyi.utils.WxConfig;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.RSAPublicKeyConfig;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RSAPublicKeyNotificationConfig;
import com.wechat.pay.java.service.partnerpayments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.partnerpayments.jsapi.model.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * @Description: TODO
 * @Create by: jacob
 * @Date: 2025/7/20
 * 遇见未来的自己
 */
@Service
public class SkmWxPayServiceImpl implements SkmWxPayService
{
    @Autowired
    private ISkmOrderPayTService skmOrderPayTService;

    public static JsapiServiceExtension service;


    @Autowired
    private RedisCache redisCache;

    @Override
    public String getBaseAccessToken() {

        String accessTokenCacheKey = CacheConstants.BASE_ACCESS_TOKEN;
        Object accessTokenObject = redisCache.getCacheObject(accessTokenCacheKey);
        if(accessTokenObject != null){
            return accessTokenObject.toString();
        }

        String accessTokenByAppidAndSecretUrl = WxUrl.ACCESS_TOKEN_BY_APPID_AND_SECRET_URL;
        accessTokenByAppidAndSecretUrl = accessTokenByAppidAndSecretUrl.replace("APPID",WxConfig.SP_APPID)
                .replace("APPSECRET",WxConfig.SP_SECRET);
        String s = HttpUtils.sendGet(accessTokenByAppidAndSecretUrl);
        JSONObject accessRes = JSONObject.parseObject(s);

        String access_token = accessRes.getString("access_token");
        int expires_in = accessRes.getIntValue("expires_in");

        redisCache.setCacheObject(accessTokenCacheKey,access_token,expires_in, TimeUnit.SECONDS);

        return access_token;
    }

    @Override
    public String getJsapiTicket() {
        String jsapiTicketKey = CacheConstants.JSAPI_TICKET ;
        Object jsapiTicketObject = redisCache.getCacheObject(jsapiTicketKey);
        if(jsapiTicketObject != null){
            return jsapiTicketObject.toString();
        }
        String baseAccessToken = this.getBaseAccessToken();
        String ticketUrl = WxUrl.JSAPI_TICKET;
        ticketUrl = ticketUrl.replace("ACCESS_TOKEN",baseAccessToken);
        String ticketStr = HttpUtils.sendGet(ticketUrl);
        JSONObject ticketJson = JSONObject.parseObject(ticketStr);

        String ticket = ticketJson.getString("ticket");
        int expires_in = ticketJson.getIntValue("expires_in");

        redisCache.setCacheObject(jsapiTicketKey,ticket,expires_in, TimeUnit.SECONDS);
        return ticket;
    }

    @Override
    public PrepayWithRequestPaymentResponse prepayWithRequestPayment(BigDecimal amountBig) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        String openid = loginUser.getUser().getOpenid();
        // 初始化商户配置
//        Config config =
//                new RSAAutoCertificateConfig.Builder()
//                        .merchantId(WxConfig.SP_MCHID)
//                        // 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥，商户私钥会用来生成请求的签名
//                        .privateKeyFromPath(WxConfig.PRIVATE_KEY_PATH)
//                        .merchantSerialNumber(WxConfig.MERCHANT_SERIAL_NUMBER)
//                        .apiV3Key(WxConfig.API_V3_KEY)
//                        .build();
// 可以根据实际情况使用publicKeyFromPath或publicKey加载公钥
        Config config =
                new RSAPublicKeyConfig.Builder()
                        .merchantId(WxConfig.SP_MCHID)
                        .privateKeyFromPath(WxConfig.PRIVATE_KEY_PATH)
                        .publicKeyFromPath(WxConfig.PUBLIC_KEY_PATH)
                        .publicKeyId(WxConfig.PUBLIC_KEY_ID)
                        .merchantSerialNumber(WxConfig.MERCHANT_SERIAL_NUMBER)
                        .apiV3Key(WxConfig.API_V3_KEY)
                        .build();
        // 初始化服务
        service = new JsapiServiceExtension.Builder()
                .config(config)
                .signType("RSA") // 不填则默认为RSA
                .build();
        // ... 调用接口
        String subMchid = "1722562509";
        String orderNo = System.currentTimeMillis()+"";
        PrepayRequest request = new PrepayRequest();
        request.setSpAppid(WxConfig.SP_APPID); // 服务商APPID
        request.setSpMchid(WxConfig.SP_MCHID); // 服务商商户号
        request.setSubMchid(subMchid); // 子商户号
        request.setDescription("测试付款");// 商品描述
        request.setOutTradeNo(orderNo); // 商户订单号
        request.setNotifyUrl(WxConfig.WX_PAY_CALLBACK_URL); // 商户回调地址
        Amount amount = new Amount();
        Integer total = (amountBig.multiply(new BigDecimal("100"))).intValue();
        amount.setTotal(total); // 【总金额】订单总金额，单位为分，整型。
        amount.setCurrency("CNY"); // 【货币类型】符合ISO 4217标准的三位字母代码，固定传：CNY，代表人民币。
        request.setAmount(amount); // 订单金额
        Payer payer = new Payer();
        payer.setSpOpenid(openid);
        request.setPayer(payer); // 支付者信息
        PrepayWithRequestPaymentResponse prepay = service.prepayWithRequestPayment(request,WxConfig.SP_APPID);
        // 生成预下单
        SkmOrderPayT skmOrderPayT = new SkmOrderPayT();
        skmOrderPayT.setMchid(subMchid);
        skmOrderPayT.setOrderAmount(amountBig);
        skmOrderPayT.setOrderNo(orderNo);
        skmOrderPayT.setOrderPayWay("01");// 微信支付
        skmOrderPayT.setOrderStatus("zfz"); // 支付中
        skmOrderPayT.setUserId(loginUser.getUserId());
        skmOrderPayTService.insertSkmOrderPayT(skmOrderPayT);
        return prepay;
//            try {
//                closeOrder();
//            } catch (HttpException e) { // 发送HTTP请求失败
//                // 调用e.getHttpRequest()获取请求打印日志或上报监控，更多方法见HttpException定义
//            } catch (ServiceException e) { // 服务返回状态小于200或大于等于300，例如500
//                // 调用e.getResponseBody()获取返回体打印日志或上报监控，更多方法见ServiceException定义
//            } catch (MalformedMessageException e) { // 服务返回成功，返回体类型不合法，或者解析返回体失败
//                // 调用e.getMessage()获取信息打印日志或上报监控，更多方法见MalformedMessageException定义
//            }
    }

    /**
     * 微信支付成功统一回调接口
     * @param request
     */
    @Override
    public ResponseEntity.BodyBuilder wxPayCallback(HttpServletRequest request) throws IOException {
        // 从请求头中获取信息
        String timestamp                        = request.getHeader("Wechatpay-Timestamp");
        String nonce                            = request.getHeader("Wechatpay-Nonce");
        String signature                        = request.getHeader("Wechatpay-Signature");
        String singType                         = request.getHeader("Wechatpay-Signature-Type");
        String wechatPayCertificateSerialNumber = request.getHeader("Wechatpay-Serial");
        System.out.println("wechatPayCertificateSerialNumber="+wechatPayCertificateSerialNumber);
        String requestBody = HttpServletRequestUtils.getRequestBody(request);

        com.wechat.pay.java.core.notification.RequestParam requestParam = new com.wechat.pay.java.core.notification.RequestParam.Builder()
                .serialNumber(wechatPayCertificateSerialNumber)
                .nonce(nonce)
                .signature(signature)
                .timestamp(timestamp)
                .body(requestBody)
                .build();

//        try {



            NotificationConfig config = new RSAPublicKeyNotificationConfig.Builder()
                    .publicKeyFromPath(WxConfig.PUBLIC_KEY_PATH)
                    .publicKeyId(WxConfig.PUBLIC_KEY_ID)
                    .apiV3Key(WxConfig.API_V3_KEY)
                    .build();


            // 初始化解析器 NotificationParser
            NotificationParser parser = new NotificationParser(config);
            // 以支付通知回调为例，验签、解密并转换成 Transaction
            Transaction transaction = parser.parse(requestParam, Transaction.class);
            System.out.println("回调返回数据："+ JSONObject.toJSONString(transaction));
            if("SUCCESS".equals(transaction.getTradeState())){
                String outTradeNo = transaction.getOutTradeNo();
                //查找订单
                SkmOrderPayT skmOrderPayT = skmOrderPayTService.selectSkmOrderPayTByOrderNo(outTradeNo);
                if(skmOrderPayT != null){
                    if("dzf".equals(skmOrderPayT.getOrderStatus()) || "zfz".equals(skmOrderPayT.getOrderStatus())){
                        skmOrderPayT.setOrderStatus("yzf");
                        skmOrderPayT.setOrderPayTime(new Date());
                        skmOrderPayT.setTransactionId(transaction.getTransactionId());
                        skmOrderPayTService.updateSkmOrderPayT(skmOrderPayT);
                        System.out.println("====处理完毕「"+outTradeNo+"」");

                        // 发起分账


                    }else{
                        System.out.println("====无需处理「"+outTradeNo+"」");
                    }

                }

            }

//
//            System.out.println("====处理完成");
//        } catch (ValidationException e) {
//            System.out.println("======"+e.getMessage());
//            // 签名验证失败，返回 401 UNAUTHORIZED 状态码
//            return ResponseEntity.status(HttpStatus.UNAUTHORIZED);
//        }catch (RuntimeException e){
//            System.out.println("======"+e.getMessage());
//            //如果处理失败，应返回 4xx/5xx 的状态码，例如 500 INTERNAL_SERVER_ERROR
//            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR);
//        }
//        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR);
        // 处理成功，返回 200 OK 状态码
        return ResponseEntity.status(HttpStatus.OK);
    }
}
